<script lang="tsx">
import type { DescriptionProps, DescInstance, DescItem } from './typing'
import type { DescriptionsProps } from 'ant-design-vue/es/descriptions/index'
// import type { CSSProperties } from 'vue';
import type { CollapseContainerOptions } from '/@/vbenComponents/Container/index'
import { defineComponent, computed, ref, unref } from 'vue'
import { get } from 'lodash-es'
import { Descriptions } from 'ant-design-vue'
import { CollapseContainer } from '/@/vbenComponents/Container/index'
// import { useDesign } from '/@/hooks/web/useDesign';
import { isFunction } from '/@/utils/is'
import { getSlot } from '/@/utils/helper/tsxHelper'
import { useAttrs } from '/@/hooks/core/useAttrs'

const props = {
  useCollapse: { type: Boolean, default: true },
  title: { type: String, default: '' },
  size: {
    type: String,
    validator: (v) => ['small', 'default', 'middle', undefined].includes(v),
    default: 'small',
  },
  bordered: { type: Boolean, default: true },
  column: {
    type: [Number, Object] as PropType<number | Recordable>,
    default: () => {
      return { xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }
    },
  },
  collapseOptions: {
    type: Object as PropType<CollapseContainerOptions>,
    default: null,
  },
  schema: {
    type: Array as PropType<DescItem[]>,
    default: () => [],
  },
  data: { type: Object },
}

export default defineComponent({
  name: 'Description',
  props,
  emits: ['register'],
  setup(props, { slots, emit }) {
    const propsRef = ref<Partial<DescriptionProps> | null>(null)

    // const { prefixCls } = useDesign('description');
    const prefixCls = 'description'
    const attrs = useAttrs()

    // Custom title component: get title
    const getMergeProps = computed(() => {
      return {
        ...props,
        ...(unref(propsRef) as Recordable),
      } as DescriptionProps
    })

    const getProps = computed(() => {
      const opt = {
        ...unref(getMergeProps),
        title: undefined,
      }
      return opt as DescriptionProps
    })

    /**
     * @description: Whether to setting title
     */
    const useWrapper = computed(() => !!unref(getMergeProps).title)

    /**
     * @description: Get configuration Collapse
     */
    const getCollapseOptions = computed((): CollapseContainerOptions => {
      return {
        // Cannot be expanded by default
        canExpand: false,
        ...unref(getProps).collapseOptions,
      }
    })

    const getDescriptionsProps = computed(() => {
      return { ...unref(attrs), ...unref(getProps) } as DescriptionsProps
    })

    /**
     * @description:设置desc
     */
    function setDescProps(descProps: Partial<DescriptionProps>): void {
      // Keep the last setDrawerProps
      propsRef.value = { ...(unref(propsRef) as Recordable), ...descProps } as Recordable
    }

    // Prevent line breaks
    function renderLabel({ label, labelMinWidth, labelStyle }: DescItem) {
      if (!labelStyle && !labelMinWidth) {
        return label
      }

      const labelStyles: CSSProperties = {
        ...labelStyle,
        minWidth: `${labelMinWidth}px `,
      }
      return <div style={labelStyles}>{label}</div>
    }

    function renderItem() {
      const { schema, data } = unref(getProps)
      return unref(schema)
        .map((item) => {
          const { render, field, span, show, contentMinWidth } = item

          if (show && isFunction(show) && !show(data)) {
            return null
          }

          const getContent = () => {
            const _data = unref(getProps)?.data
            if (!_data) {
              return null
            }
            const getField = get(_data, field)
            // 这里会报错 因此用下面一种方式处理 报错 toRefs() expects a reactive object but received a plain one.
            // if (getField && !toRefs(_data).hasOwnProperty(field)) {
            if (getField && !_data.hasOwnProperty(field)) {
              return isFunction(render) ? render('', _data) : ''
            }
            return isFunction(render) ? render(getField, _data) : getField ?? ''
          }

          const width = contentMinWidth
          // 这里做了特殊处理，
          const style: CSSProperties = {
            minWidth: `${width}px`,
          }
          return (
            <Descriptions.Item label={renderLabel(item)} key={field} span={span}>
              {!contentMinWidth ? getContent() : <div style={style}>{getContent()}</div>}
            </Descriptions.Item>
          )
          // 原来的写法如下
          // const width = contentMinWidth;
          //   return (
          //     <Descriptions.Item label={renderLabel(item)} key={field} span={span}>
          //       {() => {
          //         if (!contentMinWidth) {
          //           return getContent();
          //         }
          //         const style: CSSProperties = {
          //           minWidth: `${width}px`,
          //         };
          //         return <div style={style}>{getContent()}</div>;
          //       }}
          //     </Descriptions.Item>
          //   );
        })
        .filter((item) => !!item)
    }
    const renderDesc = () => {
      return (
        <Descriptions class={`${prefixCls}`} {...(unref(getDescriptionsProps) as any)}>
          {renderItem()}
        </Descriptions>
      )
    }

    const renderContainer = () => {
      const content = props.useCollapse ? renderDesc() : <div>{renderDesc()}</div>
      // Reduce the dom level
      if (!props.useCollapse) {
        return content
      }

      const { canExpand, helpMessage } = unref(getCollapseOptions)
      const { title } = unref(getMergeProps)
      // return (
      //   <CollapseContainer title={title} canExpan={canExpand} helpMessage={helpMessage}>
      //     {{
      //       default: () => content,
      //       action: () => getSlot(slots, 'action'),
      //     }}
      //   </CollapseContainer>
      // )
      return (
        <CollapseContainer
          title={title}
          canExpan={canExpand}
          action={() => getSlot(slots, 'action')}
          helpMessage={helpMessage}
        >
          {content}
        </CollapseContainer>
      )
    }

    const methods: DescInstance = {
      setDescProps,
    }

    emit('register', methods)
    return () => (unref(useWrapper) ? renderContainer() : renderDesc())
  },
})
</script>
